package cn.com.hhrcw.block.web;

import cn.com.hhrcw.block.entity.Block;
import cn.com.hhrcw.block.entity.BlockData;
import cn.com.hhrcw.block.mapstruct.BlockConvert;
import cn.com.hhrcw.block.mapstruct.BlockDataConvert;
import cn.com.hhrcw.block.params.BlockDataParams;
import cn.com.hhrcw.block.params.BlockParams;
import cn.com.hhrcw.block.service.IBlockDataService;
import cn.com.hhrcw.block.service.IBlockService;
import cn.com.hhrcw.block.vo.BlockDataVO;
import cn.com.hhrcw.block.vo.BlockVO;
import cn.com.hhrcw.constant.CacheConstant;
import cn.com.hhrcw.entity.EnInfo;
import cn.com.hhrcw.entity.OpJob;
import cn.com.hhrcw.es.entity.JobPositionDocument;
import cn.com.hhrcw.es.entity.RecruitmentPositionDocument;
import cn.com.hhrcw.es.entity.UniversityDocument;
import cn.com.hhrcw.es.entity.UniversitySpecialityDocument;
import cn.com.hhrcw.es.mapstruct.ElasticsearchConvert;
import cn.com.hhrcw.es.service.IElasticsearchService;
import cn.com.hhrcw.position.entity.RecruitmentPosition;
import cn.com.hhrcw.position.service.IRecruitmentPositionService;
import cn.com.hhrcw.service.IEnInfoService;
import cn.com.hhrcw.service.IOpJobService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.additional.query.impl.LambdaQueryChainWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.DictModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.core.io.ClassPathResource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Set;
import java.util.function.Function;

/**
 * 区块
 * @author lixingxing
 * @since 2020-09-16
 */
@RestController
@Slf4j
@RequestMapping("/admin/block")
@Validated
public class BlockController extends JeecgController<Block, IBlockService> {

    @Autowired
    private BlockConvert blockConvert;

    @Autowired
    private IBlockService blockService;

    @Autowired
    private IBlockDataService blockDataService;

    @Autowired
    private ISysBaseAPI sysBaseApi;

    @Autowired
    private BlockDataConvert blockDataConvert;

    @Autowired
    private IRecruitmentPositionService recruitmentPositionService;

    @Autowired
    private IOpJobService opJobService;

    @Autowired
    private ElasticsearchConvert elasticsearchConvert;

    @Autowired
    private IElasticsearchService elasticsearchService;

    @Autowired
    private IEnInfoService enInfoService;

    /**
     * 初始化搜索数据数据
     */
    @GetMapping("/init")
    public Result<?> init() throws IOException {
        //职类
        List<RecruitmentPosition> list = recruitmentPositionService.lambdaQuery().isNull(RecruitmentPosition::getPCode).list();
        list = recruitmentPositionService.lambdaQuery().in(RecruitmentPosition::getPCode, list.stream().map(RecruitmentPosition::getCode).toArray()).list();
        list = recruitmentPositionService.lambdaQuery().in(RecruitmentPosition::getPCode, list.stream().map(RecruitmentPosition::getCode).toArray()).list();
        List<RecruitmentPositionDocument> document = elasticsearchConvert.toPosition(list);
        elasticsearchService.delete(RecruitmentPositionDocument.class);
        elasticsearchService.add(document.toArray());
        //学校
        List<DictModel> models = sysBaseApi.queryDictItemsByCode("university");
        List<UniversityDocument> university = elasticsearchConvert.toUniversity(models);
        elasticsearchService.delete(UniversityDocument.class);
        elasticsearchService.add(university.toArray());
        //专业
        List<DictModel> specialities = sysBaseApi.queryDictItemsByCode("university_speciality");
        List<UniversitySpecialityDocument> specialitiesDoc = elasticsearchConvert.toSpeciality(specialities);
        elasticsearchService.delete(UniversitySpecialityDocument.class);
        elasticsearchService.add(specialitiesDoc.toArray());
        //职位
        List<OpJob> jobs = opJobService.lambdaQuery()
            .eq(OpJob::getDelFlag, false)
            .eq(OpJob::getRecruitmentState, 0)
            .list();
        JobPositionDocument[] jobPositionDocuments = jobs.stream().filter(e -> {
            EnInfo enInfo = enInfoService.getById(e.getCompanyId());
            return !enInfo.getDelFlag() && enInfo.getState() == 0 && enInfo.getEnabled();
        }).map(e -> elasticsearchConvert.toJobPosition(e, enInfoService.getById(e.getCompanyId())))
            .toArray(JobPositionDocument[]::new);
        elasticsearchService.delete(JobPositionDocument.class);
        elasticsearchService.add(jobPositionDocuments);
        //技能
        ClassPathResource resource = new ClassPathResource("skills.json");
        JSONArray array = (JSONArray) JSON.parse(IoUtil.read(resource.getInputStream(), StandardCharsets.UTF_8));
        redisTemplate.opsForValue().set("skills_all", array);
        return Result.ok();
    }

    /**
     * 区块保存
     * @param params
     * @return
     */
    @PostMapping("/saveOrUpdate")
    @AutoLog(logType = 2, ty = "update", value = "区块编辑")
    @RequiresPermissions("block:save")
    public Result<Object> save(@RequestBody BlockParams params) {
        Block block = blockConvert.toEntity(params);
        LambdaQueryChainWrapper<Block> wrapper = this.blockService.lambdaQuery().eq(Block::getCode, params.getCode());
        if (StrUtil.isNotBlank(params.getId())) {
            wrapper.ne(Block::getId, params.getId());
        }
        int count = wrapper.count();
        if (count > 0) {
            return Result.error("区块编码已存在");
        }
        blockService.saveOrUpdate(block);
        this.evict();
        return Result.ok();
    }

    /**
     * 区块列表
     * @param params
     * @param request
     * @return
     */
    @GetMapping("/list")
    @AutoLog(logType = 2, ty = "visit", value = "区块列表")
    @RequiresPermissions("block:list")
    public Result<List<BlockVO>> list(BlockParams params, HttpServletRequest request) {
        QueryWrapper<Block> queryWrapper = QueryGenerator.initQueryWrapper(new Block(), request.getParameterMap());
        queryWrapper.isNull("parent_id");
        queryWrapper.orderByAsc("sequence,create_time");
        List<Block> data = blockService.list(queryWrapper);
        List<BlockVO> list = Lists.newArrayList();
        for (Block datum : data) {
            list.add(this.child(blockConvert.toVO(datum)));
        }
        return Result.success(list);
    }


    /**
     * 区块数据列表V2
     * @param params
     * @param request
     * @return
     */
    @GetMapping("/v2/list")
    public Result<Page> listV2(BlockParams params, HttpServletRequest request) {

        QueryWrapper<Block> queryWrapper = QueryGenerator.initQueryWrapper(blockConvert.toEntity(params), request.getParameterMap());
        if (StringUtils.isBlank(params.getField())) {
            queryWrapper.orderByAsc("sequence","create_time");
        } else {
            queryWrapper.orderBy(true, params.getSort(), toUnderlineName(params.getField()));
        }
        IPage<Block> page = blockService.page(params.page(), queryWrapper);
        //分页结果转换器
        Function<Block, BlockVO> fun = block -> blockConvert.toVO(block);

        return Result.ok((Page)page.convert(fun));
    }


    /**
     * 区块删除
     * @param id
     * @return
     */
    @GetMapping("/delete")
    @AutoLog(logType = 2, ty = "delete", value = "区块删除")
    @RequiresPermissions("block:delete")
    public Result<Object> delete(@RequestParam List<String> id) {
        this.blockService.removeByIds(id);
        this.evict();
        return Result.ok();
    }

    /**
     * 区块内容
     * @param params
     * @param request
     * @return
     */
    @GetMapping("/getById")
    @AutoLog(logType = 2, ty = "visit", value = "区块信息查询")
    public Result<Page> getById(BlockParams params, HttpServletRequest request) {
        Block block = blockService.getById(params.getId());
        String defaul = "default";
        if (StrUtil.equals(block.getType(), defaul)) {
            QueryWrapper<Block> queryWrapper = QueryGenerator.initQueryWrapper(new Block(), request.getParameterMap());
            queryWrapper.eq("parent_id", params.getId());
            queryWrapper.orderByAsc("sequence");
            IPage<Block> page = blockService.page(params.page(), queryWrapper);
            return Result.success((Page)page.convert(blockConvert::toVO));
        } else {
            IPage<BlockData> blockData = blockDataService.lambdaQuery().eq(BlockData::getBlockId, block.getId()).orderByAsc(BlockData::getSequence, BlockData::getCreateTime).page(params.page());
            return Result.success((Page)blockData.convert(blockDataConvert::toVO));
        }
    }


    /**
     * 区块数据保存
     * @param params
     * @return
     */
    @PostMapping(value = {"/data/saveOrUpdateBatch","/data/saveOrUpdate"})
    @RequiresPermissions("block:data:save")
    @AutoLog(logType = 2, ty = "update", value = "区块数据保存")
    public Result<Object> blockDataSaves(@RequestBody List<BlockDataParams> params) {
        List<DictModel> dicts = sysBaseApi.queryDictItemsByCode("block_code_redirect");
        Block block = this.blockService.getById(params.get(0).getBlockId());
        List<BlockData> data = blockDataConvert.toEntity(params);
        blockDataService.saveOrUpdateBatch(data);
        this.evict();
        return Result.ok();
    }

    /**
     * 区块数据删除
     * @param id
     * @return
     */
    @GetMapping("/data/delete")
    @AutoLog(logType = 2, ty = "visit", value = "区块数据删除")
    @RequiresPermissions("block:data:delete")
    public Result<Object> dataDelete(@RequestParam List<String> id) {
        blockDataService.removeByIds(id);
        this.evict();
        return Result.ok();
    }

    /**
     * 清除缓存
     *
     * @return
     */
    @GetMapping("/evict")
    public Result evict() {
        Set keys = redisTemplate.keys(CacheConstant.BLOCK_DATA + "*");
        redisTemplate.delete(keys);
        return Result.ok();
    }

    private BlockVO child(BlockVO vo) {
        List<Block> data = blockService.lambdaQuery().eq(Block::getParentId, vo.getId()).orderByAsc(Block::getSequence, Block::getCreateTime).list();
        if (CollUtil.isEmpty(data)) {
            return vo;
        } else {
            List<BlockVO> list = blockConvert.toVO(data);
            vo.setChildren(list);
            for (BlockVO datum : list) {
                this.child(datum);
            }
        }
        return vo;
    }

}
